package cc.shacocloud.mirage.restful.bind.converter;

import cc.shacocloud.mirage.restful.HttpResponse;
import cc.shacocloud.mirage.restful.http.GenericHttpMessageConverter;
import cc.shacocloud.mirage.restful.http.HttpHeaderMap;
import cc.shacocloud.mirage.restful.http.MediaType;
import cc.shacocloud.mirage.utils.MethodParameter;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;

/**
 * {@link GenericHttpMessageConverter}实现的抽象基类。
 *
 * @param <T>转换后的对象类型
 */
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
        implements GenericHttpMessageConverter<T> {
    
    /**
     * 构造一个不支持媒体类型的{@code AbstractGenericHttpMessageConverter}。
     *
     * @see #setSupportedMediaTypes
     */
    protected AbstractGenericHttpMessageConverter() {
    }
    
    /**
     * 构造具有一种支持的媒体类型的{@code AbstractGenericHttpMessageConverter}。
     *
     * @param supportedMediaType the supported media type
     */
    protected AbstractGenericHttpMessageConverter(MediaType supportedMediaType) {
        super(supportedMediaType);
    }
    
    /**
     * 构造具有多种支持媒体类型的{@code AbstractGenericHttpMessageConverter}。
     *
     * @param supportedMediaTypes the supported media types
     */
    protected AbstractGenericHttpMessageConverter(MediaType... supportedMediaTypes) {
        super(supportedMediaTypes);
    }
    
    
    @Override
    protected boolean supports(Class<?> clazz) {
        return true;
    }
    
    @Override
    public boolean canRead(MethodParameter parameter, Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
        return (type instanceof Class ? canRead(parameter, (Class<?>) type, mediaType) : canRead(mediaType));
    }
    
    @Override
    public boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType) {
        return canWrite(clazz, mediaType);
    }
    
    /**
     * 这个实现通过调用{@link #addDefaultHeaders}来设置默认的头，然后调用{@link #writeInternal}。
     */
    @Override
    public final Future<Buffer> write(final T t,
                                      @Nullable final Type type,
                                      @Nullable MediaType contentType,
                                      HttpResponse response) {
        final HttpHeaderMap headers = response.headers();
        
        addDefaultHeaders(headers, t, contentType);
        
        return writeInternal(t, type, response);
    }
    
    @Override
    protected Future<Buffer> writeInternal(T t, HttpResponse response) {
        return writeInternal(t, null, response);
    }
    
    /**
     * 编写实际主体的抽象模板方法。从{@link #write}调用。
     *
     * @param t        要写入输出消息的对象
     * @param type     要写入的对象类型(可能是{@code null})
     * @param response 当前路由上下文
     */
    protected abstract Future<Buffer> writeInternal(T t, @Nullable Type type, HttpResponse response);
    
}
